<?php

namespace App\Macros;

use Carbon\Carbon;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Support\Collection;

class ModelTrend implements Macro
{
    protected Builder $builder;
    protected String $group_key;
    protected String $group_label = 'date';
    protected String $format = '%Y-%m-%d';

    public static function inject()
    {
        Builder::macro('trend', function($group_key, $start_date, $end_date, $count_field='count(*)'){
            return with(new ModelTrend($this, $group_key))->execute($start_date, $end_date, $count_field);
        });
    }

    public function __construct(Builder $builder, $group_key)
    {
        $this->builder = $builder;
        $this->group_key = $group_key;
    }

    public function execute($start_date, $end_date, $count_field)
    {
        $items = $this->builder->selectRaw("{$count_field} value, DATE_FORMAT({$this->group_key}, '{$this->format}') {$this->group_label}")->whereBetween('created_at', [$start_date, $end_date])->groupBy($this->group_label)->get();

        $trend = $this->fillTrendData($items, $start_date, $end_date);

        return $trend;
    }


    private function fillTrendData(Collection $row_data, $start_date, $end_date) {
        $rs = [];
        $start_date = Carbon::parse($start_date);
        $end_date = Carbon::parse($end_date);
        $current_date = $start_date;
        do{
            $date = $current_date->format(str_replace('%', '', $this->format));
            if ($match = $row_data->where('date', $date)->first()) $value = $match->value;
            else $value = 0;
            array_push($rs, compact('date', 'value'));

            $current_date = $current_date->addDay();
        }while($end_date->diffInDays($start_date) >0 );

        return $rs;
    }
}
